Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improvement: Support completions for implicit classes #5904

Merged
merged 3 commits into from
Dec 19, 2023

Conversation

tgodzik
Copy link
Contributor

@tgodzik tgodzik commented Dec 1, 2023

Previously, we would only automatically suggest extension methods, not implicit classes.

Now, we also properly suggest implicit classes.

We could follow up with support for Scala 2 also.

Connected to #5893 <- I want to close it after also fixing Scala 2

* artificial package object. Scala 2 doesn't allow for it.
*/
val isScala3Implicit =
dialect.allowExtensionMethods && currRegion.produceSourceToplevel &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to set the termOwner for current region or something to make sure we don't produce this artificial package object more than once. Though I'm not sure if that would cause any actual issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a class to input to test it. Should be correct now.

term(name, pos, Kind.OBJECT, 0)
}
owner
} else currRegion.owner
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else currRegion.owner
} else currRegion.termOwner

I think that's the one you want here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be correct now, though I had to do a couple of changes, They're in the second to last commit.

def isImplicitClass(owner: Symbol) =
val constructorParam =
owner.info.allMembers
.find(_.symbol.isAllOf(Flags.PrivateParamAccessor))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.find(_.symbol.isAllOf(Flags.PrivateParamAccessor))
.find(_.symbol.isAllOf(Flags.ParamAccessor))

It seems it doesn't have to be private and

implicit class A (val num: Int):
  def incr: Int = num + 1 

is legal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, fixed and changed one of the tests.

Comment on lines 59 to 62
owner.info.allMembers
.find(_.name == searched)
.map(_.symbol)
.toList
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't owner.info.member(termName(value)).symbol achieve the same?

Also can you in the comment mark for which part it doesn't work? (I assume you mean implicit class A, since that's the type.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but maybe with typeName instead of termName?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, changed and it works!

@@ -100,7 +100,7 @@ trait PCSuite {
case NonFatal(e) =>
println(s"warn: ${e.getMessage}")
}
workspace.inputs(filename) = (code2, dialect)
workspace.inputs(file.toURI.toString()) = (code2, dialect)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pure curiosity, why did that change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was actually showing errors whenever running tests, wasn't really problematic, but spamming the logs.

@@ -21,7 +22,12 @@ class CompilerSearchVisitor(
val logger: Logger = Logger.getLogger(classOf[CompilerSearchVisitor].getName)

private def isAccessible(sym: Symbol): Boolean = try
sym != NoSymbol && sym.isPublic && sym.isStatic
sym != NoSymbol && sym.isPublic && sym.isStatic || {
val owner = sym.maybeOwner
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we extract this part to seperate method like isAccessibleImplicit ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also check whether the symbol is accessible from site, by using the compiler's sym.isAccessibleFrom(qualType) at CompilerSearchVisitor creation site

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea @rochala though at this point it would be a much bigger refactor, so I will just move it to a method.

Comment on lines 59 to 62
owner.info.allMembers
.find(_.name == searched)
.map(_.symbol)
.toList
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but maybe with typeName instead of termName?

Previously, we would only automatically suggest extension methods, not implicit classes.

Now, we also properly suggest implicit classes.

We could follow up with support for Scala 2 also.
Copy link
Member

@jkciesluk jkciesluk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
The tests are failing, but everything looks good, I think you need to rerun save-expect

@tgodzik tgodzik force-pushed the implicit-classes branch 3 times, most recently from af70623 to 15f8b3e Compare December 18, 2023 12:19
@tgodzik tgodzik requested a review from kasiaMarek December 18, 2023 14:16
@@ -225,6 +225,15 @@ abstract class BasePCSuite extends BaseSuite with PCSuite {
}

object IgnoreScalaVersion {

def or(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added IgnoreScalaVersion#and at some point, which (counterintuitively) is the same. Maybe delete one of these.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the one I added, thanks!

package example

// This wasn't possible in Scala 2
implicit class Xtension/*example.Xtension().*//*example.Xtension#*/(number/*example.Xtension#number.*/: Int) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it's been like this all along but why do we emit a method for implicit class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't noticed it before, looks like this was done a long while ago 651a33f

And the comment is // emit symbol for implicit conversion, I guess this might no longer be needed 🤔

@tgodzik tgodzik merged commit e39acff into scalameta:main Dec 19, 2023
25 checks passed
@tgodzik tgodzik deleted the implicit-classes branch December 19, 2023 17:32
tgodzik added a commit to tgodzik/dotty that referenced this pull request Dec 20, 2023
Previously, we would only support extension methods and not the old style implicit classes. Now, those are supported also.

Introduced in scalameta/metals#5904
tgodzik added a commit to scala/scala3 that referenced this pull request Dec 21, 2023
Previously, we would only support extension methods and not the old
style implicit classes. Now, those are supported also.

Introduced in scalameta/metals#5904
odersky pushed a commit to dotty-staging/dotty that referenced this pull request Jan 6, 2024
Previously, we would only support extension methods and not the old style implicit classes. Now, those are supported also.

Introduced in scalameta/metals#5904
WojciechMazur pushed a commit to scala/scala3 that referenced this pull request Jun 25, 2024
Previously, we would only support extension methods and not the old style implicit classes. Now, those are supported also.

Introduced in scalameta/metals#5904

[Cherry-picked 3c5e216]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants